package com.vast.admin.service;

import cn.hutool.core.date.DateTime;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.vast.admin.api.BestsignOpenApi;
import com.vast.admin.api.WechatApi;
import com.vast.admin.api.entity.*;
import com.vast.admin.api.response.BestsignResponse;
import com.vast.admin.api.response.GetContractsResponse;
import com.vast.admin.api.response.SendContractResponse;
import com.vast.admin.api.response.UploadContractResponse;
import com.vast.admin.entity.*;
import com.vast.admin.entity.dto.*;
import com.vast.admin.entity.enums.OperatorEum;
import com.vast.admin.entity.enums.QueryOrderEnum;
import com.vast.admin.entity.statistics.MyContractStatisticsBean;
import com.vast.admin.mapper.ContractMapper;
import com.vast.admin.service.impl.CompanyAccountService;
import com.vast.admin.service.impl.CompanyService;
import com.vast.admin.utils.PlaceholderResolver;
import com.vast.admin.utils.QueryBuilder;
import com.vast.admin.utils.TableFieldColumnsUtils;
import com.vast.admin.utils.WordUtil;
import com.vast.common.core.domain.entity.SysRole;
import com.vast.common.core.domain.entity.SysUser;
import com.vast.common.utils.FileUtils;
import com.vast.system.common.Enviroments;
import com.vast.common.constant.MessageCode;
import com.vast.common.core.domain.Result;
import com.vast.system.domain.SysUserRole;
import com.vast.system.exception.BusinessException;
import com.vast.system.service.ISysRoleService;
import com.vast.system.service.ISysUserRoleService;
import com.vast.system.service.ISysUserService;
import com.vast.system.utils.Constant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.jodconverter.DocumentConverter;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
@Slf4j
public class ContractService extends ServiceImpl<ContractMapper, Contract> {

    @Autowired
    private BestsignOpenApi bestsignOpenApi;

    @Autowired
    private PlaceholderService placeholderService;

    @Autowired
    private CompanyService companyService;

    @Autowired
    private CustomerService customerService;

    @Autowired
    private TempleteRecordService templeteRecordService;

    @Autowired
    private TempleteService templeteService;


    @Autowired
    private DocumentConverter documentConverter;

    @Autowired
    private ContractDetailService contractDetailService;

    @Autowired
    private ContractNoService contractNoService;

    @Autowired
    private TempleteRecordSignatureService templeteRecordSignatureService;

    @Autowired
    private WechatApi wechatApi;

    @Autowired
    private CompanyAccountService companyAccountService;

    @Autowired
    private ContractDetailSignerService contractDetailSignerService;

	@Value("${ssqApi.useFace:true}")
	private boolean USE_FACE;

    @Autowired
    private ISysUserRoleService managerRoleService;

    @Autowired
    private ISysRoleService roleService;

    @Autowired
    private ISysUserService managerService;

    @Autowired
    private ContractPlaceholderService contractPlaceholderService;

    @Autowired
    private AuthService authService;

    @Autowired
    private CompanyPaymentTypeService companyPaymentTypeService;


	/**
     * 创建合同签署流程 返回合同主流程id
     * @param contractDto
     */
    @Transactional
    public Long createContract(ContractDto contractDto, SysUser manager) {
        Contract contract = new Contract();
        contract.setContractName(contractDto.getContractName());
        Company company = companyService.getById(manager.getCompanyId());
        if (company == null) {
            throw new BusinessException(new Result(MessageCode.ERROR, "未查询到企业信息"));
        }
        contract.setClientId(company.getId());
        contract.setClientName(company.getName());
        if (contractDto.getCustomerId() != null) {
            Customer customer = customerService.getById(contractDto.getCustomerId());
            if (customer == null) {
                throw new BusinessException(new Result(MessageCode.ERROR, "未查询到客户信息"));
            }
            contract.setCustomerId(customer.getId());
            contract.setCustomerName(customer.getName());
        }
        contract.setStatus("0");
        contract.setCreateBy(manager.getUserId());
        contract.setCreateTime(DateTime.now());
        super.save(contract);
        return contract.getId();
    }

    /**
     * 添加合同签署流程客户
     * @param contractDto
     */
    @Transactional
    public Long addContractCustomer(ContractDto contractDto, SysUser manager) {
        if(contractDto != null && contractDto.getContractId() != null){
            Contract contract = this.getById(contractDto.getContractId());
            if(contract != null){
                if (contractDto.getCustomerId() != null) {
                    Customer customer = customerService.getById(contractDto.getCustomerId());
                    if (customer == null) {
                        throw new BusinessException(new Result(MessageCode.ERROR, "未查询到客户信息"));
                    }
                    contract.setCustomerId(customer.getId());
                    contract.setCustomerName(customer.getName());
                    contract.setUpdateBy(manager.getUserId());
                    contract.setUpdateTime(new Date());
                }
                this.updateById(contract);
                return contract.getId();
            }else{
                throw new BusinessException(new Result(MessageCode.ERROR, "合同流程不存在"));
            }
        }
        return 0L;
    }

    /**
     * 设置合同签署者（付费者）
     * @param manager
     */
    public void setContractSigner(Long contractId, Long customerId, SysUser manager) {
        Contract contract = super.getById(contractId);
        if (contract == null) {
            throw new BusinessException(new Result(MessageCode.ERROR, "未查询到合同信息"));
        }
        Customer customer = customerService.getById(customerId);
        if (customer == null) {
            throw new BusinessException(new Result(MessageCode.ERROR, "未查询到客户信息"));
        }
        Contract updateEntity = new Contract();
        updateEntity.setId(contractId);
        updateEntity.setCustomerId(customer.getId());
        updateEntity.setCustomerName(customer.getName());
        updateEntity.setUpdateBy(manager.getUserId());
        updateEntity.setUpdateTime(new Date());
        super.updateById(updateEntity);
    }

    /**
     * 获取合同详情
     * @param contractDetailId
     * @return
     */
    public ContractDetailDto getContractDetail(Long contractDetailId) {
        ContractDetail contractDetail = contractDetailService.getById(contractDetailId);
        if (contractDetail == null) {
            throw new BusinessException(new Result(MessageCode.ERROR, "未查询到合同详情"));
        }
        ContractDetailDto contractDetailDto = new ContractDetailDto();
        contractDetailDto.setContractDetailId(contractDetailId);
        contractDetailDto.setContractId(contractDetail.getContractId());
        contractDetailDto.setTempleteId(contractDetail.getTempleteRecordId());
        contractDetailDto.setFormItems(JSONArray.parseArray(contractDetail.getFormItems()));
        List<ContractDetailSigner> contractDetailSigners = contractDetailSignerService.getByContractDetailId(contractDetailId);
        if (contractDetailSigners != null && !contractDetailSigners.isEmpty()) {
            List<ContractSignerDto> contractSigners = new ArrayList<>(contractDetailSigners.size());
            for (ContractDetailSigner contractDetailSigner : contractDetailSigners) {
                contractSigners.add(new ContractSignerDto(contractDetailSigner.getSignerIndex(), contractDetailSigner.getPartName(), contractDetailSigner.getSignerId()));
            }
            contractDetailDto.setContractSigners(contractSigners);
        }
        return contractDetailDto;
    }

    /**
     * 保存添加的合同模板及采集到的的合同模板参数信息
     * @param contractDetailDto
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean saveContractDetail(ContractDetailDto contractDetailDto, SysUser manager) {
        boolean result = false;
        Contract contract = super.getById(contractDetailDto.getContractId());
        if (contract == null) {
            throw new BusinessException(new Result(MessageCode.ERROR, "未查询到合同"));
        }
        if (!"0".equals(contract.getStatus())) {
            throw new BusinessException(new Result(MessageCode.ERROR, "当前合同无法添加新的合同模板"));
        }
        TempleteRecord templeteRecord = templeteRecordService.getById(contractDetailDto.getTempleteId());
        if (templeteRecord == null) {
            throw new BusinessException(new Result(MessageCode.ERROR, "未查询到合同模板"));
        }
        Company company = companyService.getById(manager.getCompanyId());
        if (company == null) {
            throw new BusinessException(new Result(MessageCode.ERROR, "未查询到企业信息"));
        }
        ContractDetail contractDetail = new ContractDetail();
        contractDetail.setClientId(company.getId());
        if (contractDetailDto.getContractSigners() != null && !contractDetailDto.getContractSigners().isEmpty()) {
            for (ContractSignerDto contractSignerDto : contractDetailDto.getContractSigners()) {
                if (placeholderService.isContains(templeteRecord.getCompanyPart(), contractSignerDto.getPartName())) {
                    if (StringUtils.hasText(contractDetail.getPartyA())) {
                        contractDetail.setPartyA(contractDetail.getPartyA() + "," + contractSignerDto.getCustomerId());
                    } else {
                        contractDetail.setPartyA(contractSignerDto.getCustomerId() + "");
                    }
                } else if (placeholderService.isContains(templeteRecord.getCustomerPart(), contractSignerDto.getPartName())) {
                    if (StringUtils.hasText(contractDetail.getPartyB())) {
                        contractDetail.setPartyB(contractDetail.getPartyB() + "," + contractSignerDto.getCustomerId());
                    } else {
                        contractDetail.setPartyB(contractSignerDto.getCustomerId() + "");
                    }
                } else if (placeholderService.isContains(templeteRecord.getThirdPart(), contractSignerDto.getPartName())) {
                    if (StringUtils.hasText(contractDetail.getPartyC())) {
                        contractDetail.setPartyC(contractDetail.getPartyC() + "," + contractSignerDto.getCustomerId());
                    } else {
                        contractDetail.setPartyC(contractSignerDto.getCustomerId() + "");
                    }
                }
            }
        }
        contractDetail.setContractId(contract.getId());
        contractDetail.setTempleteId(templeteRecord.getTempleteId());
        contractDetail.setTempleteRecordId(templeteRecord.getId());
        contractDetail.setCreateBy(manager.getUserId());
        contractDetail.setStatus(0);
        contractDetail.setContractParam(new Gson().toJson(contractDetailDto.getParam()));
        if (contractDetailDto.getFormItems() != null) {
            contractDetail.setFormItems(contractDetailDto.getFormItems().toJSONString());
        }

        if (contractDetailDto.getContractDetailId() != null) {
            contractDetail.setUpdateBy(manager.getUserId());
            contractDetail.setUpdateTime(new Date());
            contractDetail.setId(contractDetailDto.getContractDetailId());
            result = contractDetailService.updateById(contractDetail);
        } else {
            contractDetail.setCreateBy(manager.getUserId());
            contractDetail.setCreateTime(new Date());
            result = contractDetailService.save(contractDetail);
        }

        if (contractDetailDto.getContractSigners() != null && !contractDetailDto.getContractSigners().isEmpty()) {
            List<ContractDetailSigner> contractDetailSigners = new ArrayList<>(contractDetailDto.getContractSigners().size());
            for (ContractSignerDto contractSignerDto : contractDetailDto.getContractSigners()) {
                ContractDetailSigner contractDetailSigner = new ContractDetailSigner();
                contractDetailSigner.setContractId(contract.getId());
                contractDetailSigner.setContractDetailId(contractDetail.getId());
                if (placeholderService.isContains(templeteRecord.getCompanyPart(), contractSignerDto.getPartName())) {
                    contractDetailSigner.setPartType(1);
                } else if (placeholderService.isContains(templeteRecord.getCustomerPart(), contractSignerDto.getPartName())) {
                    contractDetailSigner.setPartType(2);
                } else if (placeholderService.isContains(templeteRecord.getThirdPart(), contractSignerDto.getPartName())) {
                    contractDetailSigner.setPartType(3);
                } else {
                    contractDetailSigner.setPartType(0);
                }
                contractDetailSigner.setPartName(contractSignerDto.getPartName());
                contractDetailSigner.setSignerId(contractSignerDto.getCustomerId());
                contractDetailSigner.setSignerIndex(contractSignerDto.getIndex());
                contractDetailSigners.add(contractDetailSigner);
            }
            contractDetailSignerService.deleteByContractDetailId(contractDetail.getId());
            result = contractDetailSignerService.saveBatch(contractDetailSigners);
        }
        return result;
    }

    /**
     * 合同采集完成提交及合同生成
     * @param contractId
     * @param manager
     */
    @Transactional(rollbackFor = Exception.class)
    public void productionContract(Long contractId, SysUser manager, Integer flag) {
        Company company = companyService.getById(manager.getCompanyId());
        Contract contract = super.getById(contractId);
        //还款计划
        Map<Long, Loan> loanMap = new HashMap<>();
        if (contract == null) {
            throw new BusinessException(new Result(MessageCode.ERROR, "未查询到合同"));
        }
        if (contract.getCustomerId() == null) {
            throw new BusinessException(new Result(MessageCode.ERROR, "未指定合同签署者"));
        }
        if (contract.getIsPay() == 0) {
            List<ContractDetail> contractDetails = contractDetailService.getByContractId(contractId);
            if (contractDetails.size() == 0) {
                throw new BusinessException(new Result(MessageCode.ERROR, "未添加合同模板"));
            }
            checkContract(contract, contractDetails, loanMap, flag);
            //合同编号
            String contractNo = contractNoService.getContractNo(company.getContractCode());

            //合同总金额
            double amount = 0D;

            Gson gson = new Gson();
            if (contractDetails.size() > 0) {
                for (ContractDetail contractDetail : contractDetails) {
                    TempleteRecord templeteRecord = templeteRecordService.getByTempleteId(contractDetail.getTempleteId());
                    if (templeteRecord == null) {
                        throw new BusinessException(new Result(MessageCode.ERROR, "未找到所选合同模板"));
                    }
                    Long current = System.currentTimeMillis();
                    String contractWordPath = FileUtils.getContractPath() + current + ".docx";
                    String contractPdfPath = FileUtils.getContractPath() + current + ".pdf";

                    Map<String, String> contractParam = null;
                    try {
                        contractParam = gson.fromJson(contractDetail.getContractParam(), new TypeToken<Map<String, String>>(){}.getType());
                    } catch (Exception e) {
                        log.error("合同{} 参数异常, contractParam={}", contractId, contractDetail.getContractParam());
                        throw new BusinessException("合同参数异常");
                    }

                    Map<String, Object> paramMap = placeholderService.resolverParam(contractDetail.getTempleteRecordId(), contractParam);
                    try {
                        contractPlaceholderService.saveContractPlaceholder(contractDetail.getContractId(), contractDetail.getId(), contractDetail.getTempleteRecordId(), contractParam);
                    } catch (Exception e) {
                        log.error("contractPlaceholder 解析异常 contractDetailId：" + contractDetail.getId(), e);
                    }

                    //系统合同编号
                    if (paramMap.containsKey(PlaceholderResolver.CONTRACT_NO_FIELD)) {
                        paramMap.put(PlaceholderResolver.CONTRACT_NO_FIELD, contractNo);
                    }
                    //还款计划
                    if (loanMap.containsKey(contractDetail.getId())) {
                        paramMap.put(PlaceholderResolver.REPAYMENT_PLAN_FIELD.replace("#", ""), WordUtil.generateRepaymentPlanData(loanMap.get(contractDetail.getId()).getRepaymentPlanWords()));
                    }

                    //通过模板文件生成合同word文档
                    WordUtil.replacePlaceholder(FileUtils.getLocation() + templeteRecord.getTempletePath(), FileUtils.getLocation() + contractWordPath, paramMap);
                    //word文档转pdf文件
                    File word = new File(FileUtils.getLocation() + contractWordPath);
                    File pdf = new File(FileUtils.getLocation() + contractPdfPath);
                    ContractDetail updateEntity = new ContractDetail();
                    PDDocument pdDocument = null;
                    try {
                        documentConverter.convert(word).to(pdf).execute();
                        pdDocument = PDDocument.load(pdf);
                        updateEntity.setPdfPage(pdDocument.getNumberOfPages());
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                        throw new BusinessException(new Result(MessageCode.ERROR, "合同文件生成失败"));
                    } finally {
                        try {
                            pdDocument.close();
                        } catch (IOException e) {
                            log.error(e.getMessage(), e);
                        }
                    }

                    //删除word文件
                    word.delete();
                    //保存pdf文件路径
                    updateEntity.setId(contractDetail.getId());
                    updateEntity.setPdfPath(contractPdfPath);
                    updateEntity.setContractParam(gson.toJson(paramMap));
                    updateEntity.setStatus(1);
                    updateEntity.setUpdateBy(manager.getUserId());
                    updateEntity.setUpdateTime(new Date());
                    contractDetailService.updateById(updateEntity);


                    String value;
                    try {
                        value = placeholderService.getValueByTag(updateEntity.getContractParam(), contractDetail.getTempleteRecordId(), 10);
                    } catch (Exception e) {
                        log.error("获取合同金额失败", e);
                        value = null;
                    }
                    if (StringUtils.hasText(value) && org.apache.commons.lang3.StringUtils.isNumeric(value)) {
                        amount += Double.parseDouble(value);
                    }
                }
            } else {
                //无合同信息，异常提交
                throw new BusinessException(new Result(MessageCode.ERROR, "无合同信息"));
            }
            //保存合同流程信息
            Contract updateEntity = new Contract();
            updateEntity.setId(contractId);
            updateEntity.setContractNo(contractNo);
            updateEntity.setAmount(amount);
            updateEntity.setStatus("2");
            updateEntity.setUpdateBy(manager.getUserId());
            updateEntity.setUpdateTime(new Date());
            super.updateById(updateEntity);
            //合同计费及支付
            payContract(contractId, company, manager);
        } else {
            //合同已付费，检查合同中签署人是否已实名认证
            if (checkRealname(contract.getId())) {
                //上传合同到上上签
                uploadContract(contract.getId());
            }
        }
    }


    /**
     * 检查合同：
     * 1.检查签署者是否已设置
     * 2.检查合同是否包含#还款计划表，生成还款计划表所需的字段是否有填写， 并生成还款计划
     * @param contract
     * @param contractDetails
     */
    private void checkContract(Contract contract, List<ContractDetail> contractDetails, Map<Long, Loan> loanMap, Integer isCheckSigner) {
        // 1.检查签署者是否已设置
        checkSigner(contract, contractDetails, isCheckSigner);
        // 2.检查合同是否包含#还款计划表，生成还款计划表所需的字段是否有填写
        checkRepaymentPlan(contractDetails, loanMap);
    }

    /**
     * 检查合同签署者是否设置合法
     * @param contract
     * @param contractDetails
     * @param isCheckSigner 0检查 1不检查
     */
    private void checkSigner(Contract contract, List<ContractDetail> contractDetails, Integer isCheckSigner) {
        if (isCheckSigner == 0) {
            //检查是否有签署方未设置
            Map<Long, List<String>> map = new HashMap<>();
            for (ContractDetail contractDetail : contractDetails) {
                List<TempleteRecordSignature> tmp = templeteRecordSignatureService.getByTempleteRecordId(contractDetail.getTempleteRecordId());
                if (tmp != null && tmp.size() > 0) {
                    for (TempleteRecordSignature templeteRecordSignature : tmp) {
                        boolean flag = false;
                        List<ContractDetailSigner> contractDetailSigners = contractDetailSignerService.getByContractDetailId(contractDetail.getId());
                        for (ContractDetailSigner contractDetailSigner : contractDetailSigners) {
                            if (templeteRecordSignature.getPartName().equals(contractDetailSigner.getPartName())){
                                flag = true;
                                break;
                            }
                        }
                        if (!flag){
                            if (map.containsKey(contractDetail.getTempleteId())) {
                                map.get(contractDetail.getTempleteId()).add(templeteRecordSignature.getPartName());
                            } else {
                                List<String> list = new ArrayList<>();
                                list.add(templeteRecordSignature.getPartName());
                                map.put(contractDetail.getTempleteId(), list);
                            }
                        }
                    }
                }
            }
            if (!map.isEmpty()) {
                String msg = "";
                for (Map.Entry<Long, List<String>> entry : map.entrySet()) {
                    Templete templete = templeteService.getById(entry.getKey());
                    if (!"".equals(msg)) {
                        msg += ",";
                    }
                    msg += templete.getTempleteName() + "中" + org.apache.commons.lang3.StringUtils.join(entry.getValue(), "、");
                }
                msg += "未设置";
                throw new BusinessException(new Result(MessageCode.PARAM_ERROR, msg));
            }
        }

        //检查是否有已输入姓名但未通过电话号码筛选用户的签署方
        Gson gson = new Gson();
        String msg = "";
        for (ContractDetail contractDetail : contractDetails) {
            Map<String, String> contractParam = null;
            try {
                contractParam = gson.fromJson(contractDetail.getContractParam(), new TypeToken<Map<String, String>>(){}.getType());
            } catch (Exception e) {
                log.error("合同{} 参数异常, contractParam={}", contract.getContractName(), contractDetail.getContractParam());
                throw new BusinessException("合同参数异常");
            }
            //当前合同详情对应的签署方
            List<TempleteRecordSignature> templeteRecordSignatures = templeteRecordSignatureService.getByTempleteRecordId(contractDetail.getTempleteRecordId());
            for (TempleteRecordSignature templeteRecordSignature : templeteRecordSignatures) {
                //查询出签署方对应的所有占位符
                List<Placeholder> placeholders = placeholderService.getPlaceholderByBelong(contractDetail.getTempleteRecordId(), templeteRecordSignature.getPartName());
                if (placeholders == null || placeholders.isEmpty()) {
                    continue;
                }
                String placeholderBelongMsg = null;
                for (Placeholder placeholder : placeholders) {
                    //当占位符对应的任一参数有值且未设置该签署方的签署用户时
                    if (StringUtils.hasText(contractParam.get(placeholder.getPlaceholderKey())) && !contractDetailSignerService.isContainSigner(contractDetail.getId(), templeteRecordSignature.getPartName())) {
                        if (placeholderBelongMsg == null) {
                            placeholderBelongMsg = placeholder.getPlaceholderBelong();
                        } else {
                            placeholderBelongMsg += "、" + placeholder.getPlaceholderBelong();
                        }
                    }
                }
                if (placeholderBelongMsg != null) {
                    Templete templete = templeteService.getById(contractDetail.getTempleteId());
                    msg += "合同" + templete.getTempleteName() + "中签署方" + placeholderBelongMsg;
                }
            }
        }
        if (StringUtils.hasText(msg)) {
            msg += "有填写信息但未设置签署用户";
            throw new BusinessException(msg);
        }
    }

    /**
     * 检查还款计划相关字段
     * @param contractDetails
     * @param loanMap
     */
    private void checkRepaymentPlan(List<ContractDetail> contractDetails, Map<Long, Loan> loanMap) {
        for (ContractDetail contractDetail : contractDetails) {
            if (placeholderService.getPlaceholderByName(contractDetail.getTempleteRecordId(), PlaceholderResolver.REPAYMENT_PLAN_FIELD) != null) {
                Loan loan = new Loan();
                loan.setContractDetailId(contractDetail.getId());
                List<ContractForm> contractForms = new Gson().fromJson(contractDetail.getFormItems(), new TypeToken<List<ContractForm>>(){}.getType());
                for (ContractForm contractForm : contractForms) {
                    for (ContractFormItem contractFormItem : contractForm.getItems()) {
                        switch (contractFormItem.getPlaceholderTag().intValue()) {
                            //6借款期数 7月利率 8还款方式 9每月还款日 10合同金额
                            case 6:
                                try {
                                    loan.setRepaymentPeriod(Integer.parseInt(contractFormItem.getValue()));
                                } catch (NumberFormatException e) {
                                    throw new BusinessException(new Result(MessageCode.ERROR, contractFormItem.getPlaceholderName() + "必须为数字"));
                                }
                                break;
                            case 7:
                                String value = contractFormItem.getValue();
                                value = value.replace("%", "");
                                try {
                                    double num = Double.parseDouble(value);
                                    loan.setMonthlyInterest(num / 100);
                                } catch (NumberFormatException e) {
                                    throw new BusinessException(new Result(MessageCode.ERROR, contractFormItem.getPlaceholderName() + "必须为数字"));
                                }
                                break;
                            case 8:
                                loan.setRepaymentMethod(contractFormItem.getValue());
                                break;
                            case 9:
                                try {
                                    loan.setMonthlyRepaymentDate(Integer.parseInt(contractFormItem.getValue()));
                                } catch (NumberFormatException e) {
                                    throw new BusinessException(new Result(MessageCode.ERROR, contractFormItem.getPlaceholderName() + "必须为数字"));
                                }
                                break;
                            case 10:
                                try {
                                    loan.setContractAmount(Double.parseDouble(contractFormItem.getValue()));
                                } catch (NumberFormatException e) {
                                    throw new BusinessException(new Result(MessageCode.ERROR, contractFormItem.getPlaceholderName() + "必须为数字"));
                                }
                                break;
                        }
                    }
                }
                loan.generateRepaymentPlan();
                loanMap.put(contractDetail.getId(), loan);
            }
        }
    }


    /**
     * 合同付费
     */
    private void payContract(Long contractId, Company company, SysUser manager) {
        Contract contract = super.getById(contractId);
        if (contract.getIsPay() == 0) {
            Double amount = calculateContractAmount(contract, company);
            Contract updateEntity = new Contract();
            updateEntity.setId(contract.getId());
            updateEntity.setContractAmount(amount);
            Customer customer = customerService.getById(contract.getCustomerId());
            if (Enviroments.isProd) {
                if (company.getPaymentMethod().intValue() == 1) {
                    //客户付费
                    wechatApi.pushPayMsg(customer.getWxId(), amount, contract.getContractName(), contractId);
                    updateEntity.setStatus("2");
                } else {
                    //企业预存账户扣除
                    companyAccountService.payContract(contract, company, amount, manager);
                    updateEntity.setIsPay(1);
                    updateEntity.setStatus("3");
                    //合同已付费，检查合同中签署人是否已实名认证
                    if (checkRealname(contract.getId())) {
                        //上传合同到上上签
                        uploadContract(contract.getId());
                    }
                }
            } else {
                updateEntity.setIsPay(1);
                updateEntity.setStatus("3");
                //合同已付费，检查合同中签署人是否已实名认证
                if (checkRealname(contract.getId())) {
                    //上传合同到上上签
                    uploadContract(contract.getId());
                }
            }
            super.updateById(updateEntity);
        }
    }

    /**
     * 计算合同付费金额
     */
    private Double calculateContractAmount(Contract contract, Company company) {
        Double amount = 0D;
        List<ContractDetail> contractDetails = contractDetailService.getByContractId(contract.getId());
        for (ContractDetail contractDetail : contractDetails) {
            TempleteRecord templeteRecord = templeteRecordService.getById(contractDetail.getTempleteRecordId());
            //从合同中获取金额
            String value = placeholderService.getValueByTag(contractDetail.getContractParam(), templeteRecord.getId(), 10);
            if (company.getPaymentType() == 1) {
                //按合同模板计费
                if (templeteRecord.getCostType().intValue() == 2) {
                    //合同金额计费方式
                    if (StringUtils.isEmpty(value)) {
                        throw new BusinessException(new Result(MessageCode.ERROR, "合同模板未设置合同总金额参数或合同总金额参数未填写"));
                    }
                    Double ratio = templeteRecord.getPayRatio();
                    if (ratio == null || ratio < 0) {
                        throw new BusinessException(new Result(MessageCode.ERROR, "合同模板中合同金额比例未设置或设置异常，请检查"));
                    }
                    //四舍五入保留两位
                    Double tmp = new BigDecimal(Double.parseDouble(value))
                            .multiply(new BigDecimal(templeteRecord.getPayRatio()))
                            .setScale(2, RoundingMode.HALF_UP)
                            .doubleValue();
                    if (tmp < templeteRecord.getMinAmount()) {
                        tmp = templeteRecord.getMinAmount();
                    }
                    if (tmp > amount) {
                        amount = tmp;
                    }
                } else {
                    //模板计费方式
                    if (templeteRecord.getPayAmount() != null && templeteRecord.getPayAmount() > amount) {
                        amount = templeteRecord.getPayAmount();
                    }
                }
            } else if (company.getPaymentType() == 2) {
                //按合同金额区间计费
                if (StringUtils.isEmpty(value)) {
                    continue;
                }
                //临时修改成区间按阶级计费 2021年4月27日16:55:04 待后续确认需求后再说
//                Double tmp = companyPaymentTypeService.getByAmount(company.getId(), Double.parseDouble(value));
                Double tmp = companyPaymentTypeService.getByStep(company.getId(), Double.parseDouble(value));
                if (tmp > amount) {
                    amount = tmp;
                }
            } else if (company.getPaymentType() == 3) {
                //按合同金额阶级计费
                if (StringUtils.isEmpty(value)) {
                    continue;
                }
                Double tmp = companyPaymentTypeService.getByStep(company.getId(), Double.parseDouble(value));
                if (tmp > amount) {
                    amount = tmp;
                }
            }
        }
        if (amount == 0D) {
            log.warn("合同id[{}] 合同名称[{}] 的合同 收费金额为0", contract.getId(), contract.getContractName());
        }
        return amount;
    }

    /**
     * 检查改合同中的客户是否都已完成实名认证，对未实名认证的客户推送实名认证链接
     * @param contractId
     * @return
     */
    private boolean checkRealname(Long contractId) {
        boolean result = true;
        List<ContractDetail> contractDetails = contractDetailService.getByContractId(contractId);
        String customerIds = null;
        for (ContractDetail contractDetail : contractDetails) {
            //检查客户方是否已完成实名认证
            String partBIds = contractDetail.getPartyB();

//            if (!isPushRealnameUrl(partBIds, contractId)) {
//                result = false;
//            }
            //检查丙方是否已完成实名认证
            String partCIds = contractDetail.getPartyC();
//            if (!isPushRealnameUrl(partCIds, contractId)) {
//                result = false;
//            }

            customerIds = contactStr(contactStr(customerIds, partBIds), partCIds);
        }

        if (!isPushRealnameUrl(customerIds, contractId)) {
            result = false;
        }
        return result;
    }

    private String contactStr(String s1, String s2) {
        if (StringUtils.hasText(s1) && StringUtils.hasText(s2)) {
            return s1 + "," + s2;
        } else if (!StringUtils.hasText(s1) && StringUtils.hasText(s2)) {
            return s2;
        } else if (StringUtils.hasText(s1) && !StringUtils.hasText(s2)) {
            return s1;
        } else {
            return null;
        }
    }

    /**
     * 检查是否需要推送实名认证链接
     * @param ids
     * @param contractId
     * @return
     */
    private boolean isPushRealnameUrl(String ids, Long contractId) {
        boolean result = true;
        if (StringUtils.hasText(ids)) {
            String[] idArry = removeDuplicateCustomerId(ids).split(",");
            for (String id : idArry) {
                Long customerId = Long.parseLong(id);
                Customer customer = customerService.getById(customerId);
                if (customer == null) {
                    log.warn("合同（contractId={}）中的签署者（customerId={}）未找到", contractId, customerId);
                    continue;
                }
                if (customer.getRealnameStatus().intValue() != 1) {
                    result = false;
                    customerService.pushRealnameUrl(customerId, contractId);
                }
            }
        }
        return result;
    }

    /**
     * 上传合同到上上签
     * @param contractId 合同id
     */
    @Transactional(rollbackFor = Exception.class)
    public void uploadContract(Long contractId) {
        Contract contract = super.getById(contractId);
        if (contract == null) {
            throw new BusinessException(new Result(MessageCode.ERROR, "未查询到合同信息, contractId=" + contractId));
        }
        if ("4".equals(contract.getStatus())) {
            throw new BusinessException("该合同已签署完成, contractId=" + contractId);
        }
        Company company = companyService.getById(contract.getClientId());
        List<ContractDetail> contractDetails = contractDetailService.getByContractId(contractId);
        if (contractDetails == null || contractDetails.isEmpty()) {
            throw new BusinessException(new Result(MessageCode.ERROR, "未查询到合同信息"));
        }
        for (ContractDetail contractDetail : contractDetails) {
            if (contractDetail.getStatus() == 2 || contractDetail.getStatus() == 3) {
                log.warn("contractId={}合同已上传到上上签，无法重复上传", contractId);
                return;
            }
        }
        if (contractDetails.size() == 1) {
            //单文档合同
            ContractDetail contractDetail = contractDetails.get(0);
            File file = new File(FileUtils.getLocation() + contractDetail.getPdfPath());
            try (FileInputStream fis = new FileInputStream(file)) {
                byte[] bdata = IOUtils.toByteArray(fis);
                String fdata = Base64.encodeBase64String(bdata);
                String fmd5 = DigestUtils.md5Hex(bdata);
                UploadContract uploadContract = new UploadContract();
                uploadContract.setAccount(company.getBestsignAccount());
                uploadContract.setTitle(contract.getContractName());
                uploadContract.setFname(file.getName());
                uploadContract.setFdata(fdata);
                uploadContract.setFmd5(fmd5);
                uploadContract.setFpages(contractDetail.getPdfPage() + "");
                BestsignResponse<UploadContractResponse> bestsignResponse = bestsignOpenApi.uploadContract(uploadContract);
                String bestsignContractId = bestsignResponse.getData().getContractId();
                ContractDetail updateEntity = new ContractDetail();
                updateEntity.setId(contractDetail.getId());
                updateEntity.setBestsignContractId(bestsignContractId);
                contractDetailService.updateById(updateEntity);
                //企业自动签署
                signContract(bestsignContractId, contractDetail, contract);
                //设置客户签署参数
                setSignSetting(bestsignContractId, contractDetail);
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        } else if (contractDetails.size() > 1) {
            //多文档合同
            CreateCatalog createCatalog = new CreateCatalog();
            createCatalog.setCatalogName(getBestsignCatalogName(contractId));
            //创建合同目录
            bestsignOpenApi.createCatalog(createCatalog);
            int i = 1;
            for (ContractDetail contractDetail : contractDetails) {
                UploadCatalogContract uploadCatalogContract = new UploadCatalogContract();
                uploadCatalogContract.setCatalogName(getBestsignCatalogName(contractId));
                uploadCatalogContract.setTitle(contract.getContractName() + i);
                File file = new File(FileUtils.getLocation() + contractDetail.getPdfPath());
                try (FileInputStream fis = new FileInputStream(file)) {
                    byte[] bdata = IOUtils.toByteArray(fis);
                    String fdata = Base64.encodeBase64String(bdata);
                    String fmd5 = DigestUtils.md5Hex(bdata);
                    uploadCatalogContract.setFmd5(fmd5);
                    uploadCatalogContract.setFname(file.getName());
                    uploadCatalogContract.setFpages(contractDetail.getPdfPage() + "");
                    uploadCatalogContract.setFdata(fdata);
                    bestsignOpenApi.uploadCatalogContract(uploadCatalogContract);
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
                i ++;
            }
            //获取上传的合同
            GetContractsResponse getContractsResponse = bestsignOpenApi.getContracts(new CatalogName(getBestsignCatalogName(contractId))).getData();
            Map<String, Map<String, String>> map = getContractsResponse.getContracts();
            i = 1;
            for (ContractDetail contractDetail : contractDetails) {
                String bestsignContractId = map.get(contract.getContractName() + i).get("contractId");
                ContractDetail updateEntity = new ContractDetail();
                updateEntity.setId(contractDetail.getId());
                updateEntity.setBestsignContractId(bestsignContractId);
                contractDetailService.updateById(updateEntity);
                contractDetail.setBestsignContractId(bestsignContractId);
                //企业自动签署
                signContract(bestsignContractId, contractDetail, contract);
//                //设置客户签署参数
//                setSignSetting(bestsignContractId, contractDetail);
                i ++;
            }

        } else {
            throw new BusinessException(new Result(MessageCode.ERROR, "未添加合同模板"));
        }
        //推送签署链接
        sendContract(contractId, company);
    }

    /**
     * 企业自动签署合同
     */
    private void signContract(String bestsignContractId, ContractDetail contractDetail, Contract contract) {
        if (StringUtils.isEmpty(contractDetail.getPartyA())) {
            log.warn("合同【{}】无企业方", contract.getContractNo());
            return;
        }
        List<ContractDetailSigner> contractDetailSigners = contractDetailSignerService.getContractDetailSigners(contractDetail.getContractId(), contractDetail.getId(), 1);
        List<Long> signedCompany = new ArrayList<>();
        if (contractDetailSigners == null || contractDetailSigners.isEmpty()) {
            log.warn("合同【{}】无企业方", contract.getContractNo());
            return;
        }
        for (ContractDetailSigner contractDetailSigner : contractDetailSigners) {
            if (signedCompany.contains(contractDetailSigner.getSignerId())) {
                continue;
            }
            SignContract signContract = new SignContract();
            signContract.setContractId(bestsignContractId);
            //获取企业上上签账号
            Company company = companyService.getById(contractDetailSigner.getSignerId());
            signContract.setSignerAccount(company.getBestsignAccount());
            //获取签章坐标
            List<TempleteRecordSignature> templeteRecordSignatures = templeteRecordSignatureService.getTempleteRecordSignatures(contractDetail.getTempleteRecordId(), 1, contractDetailSigner.getPartName());
            if (templeteRecordSignatures == null || templeteRecordSignatures.isEmpty()) {
                throw new BusinessException("未获取到合同模板的签章坐标信息");
            }
            for (TempleteRecordSignature templeteRecordSignature : templeteRecordSignatures) {
                signContract.add(templeteRecordSignature.getPage(), templeteRecordSignature.getX(), templeteRecordSignature.getY());
            }
            bestsignOpenApi.signContract(signContract);
            contractDetailSignerService.signed(contractDetailSigner.getId());
            signedCompany.add(contractDetailSigner.getSignerId());
        }
    }

    /**
     * 设置客户手动签 签署参数及签署人
     */
    private void setSignSetting(String bestsignContractId, ContractDetail contractDetail) {
        if (StringUtils.hasText(contractDetail.getPartyB())) {
            setSignerConfig(bestsignContractId, contractDetail, 2);
        }
        if (StringUtils.hasText(contractDetail.getPartyC())) {
            setSignerConfig(bestsignContractId, contractDetail, 3);
        }
    }

    private void setSignerConfig(String bestsignContractId, ContractDetail contractDetail, Integer type) {
        List<ContractDetailSigner> contractDetailSigners = contractDetailSignerService.getContractDetailSigners(contractDetail.getContractId(), contractDetail.getId(), type);
        if (contractDetailSigners == null || contractDetailSigners.isEmpty()) {
            return;
        }
        for (ContractDetailSigner contractDetailSigner : contractDetailSigners) {
            Customer customer = customerService.getById(contractDetailSigner.getSignerId());
            //将用户添加为合同的签署者
            bestsignOpenApi.addSigner(new AddSigner(bestsignContractId, customer.getAccount()));
            SetSignerConfig setSignerConfig = new SetSignerConfig();
            setSignerConfig.setContractId(bestsignContractId);
            setSignerConfig.setAccount(customer.getAccount());
            setSignerConfig.setVcodeMobile(customer.getMobile());
            if (!USE_FACE) {
                setSignerConfig.setIsFaceAuth("0");
            }
            List<TempleteRecordSignature> templeteRecordSignatures = templeteRecordSignatureService.getTempleteRecordSignatures(contractDetail.getTempleteRecordId(), type, contractDetailSigner.getPartName());
            if (templeteRecordSignatures == null || templeteRecordSignatures.isEmpty()) {
                throw new BusinessException("未获取到合同模板的签名坐标信息");
            }
            for (TempleteRecordSignature templeteRecordSignature : templeteRecordSignatures) {
                setSignerConfig.add(templeteRecordSignature.getPage(), templeteRecordSignature.getX(), templeteRecordSignature.getY());
            }
            bestsignOpenApi.setSignerConfig(setSignerConfig);
        }
    }

    /**
     * 获取手动签url推送到用户
     */
    private void sendContract(Long contractId, Company company) {
        Contract contract = super.getById(contractId);
        List<ContractDetail> contractDetails = contractDetailService.getByContractId(contractId);
        if (contractDetails.size() == 1) {
            //单文档
            ContractDetail contractDetail = contractDetails.get(0);
            //客户方签署推送
            pushSingleContractUrl(contractDetail.getPartyB(), contractDetail.getBestsignContractId(), contract.getContractName(), company.getName());
            //第三方 丙方 签署推送
            pushSingleContractUrl(contractDetail.getPartyC(), contractDetail.getBestsignContractId(), contract.getContractName(), company.getName());
        } else {
            //多文档
            List<Long> partB = new ArrayList<>();
            List<Long> partC = new ArrayList<>();
            for (ContractDetail contractDetail : contractDetails) {
                if (StringUtils.hasText(contractDetail.getPartyB())) {
                    for (String id : contractDetail.getPartyB().split(",")) {
                        Long customerId = Long.parseLong(id);
                        if (!partB.contains(customerId)) {
                            partB.add(customerId);
                        }
                    }
                }
                if (StringUtils.hasText(contractDetail.getPartyC())) {
                    for (String id : contractDetail.getPartyC().split(",")) {
                        Long customerId = Long.parseLong(id);
                        if (!partC.contains(customerId)) {
                            partC.add(customerId);
                        }
                    }
                }
            }
            //客户方签署推送
            pushMultiContractUrl(StringUtils.collectionToCommaDelimitedString(partB), contractId, contract.getContractName(), company.getName(), 2, contractDetails);
            //第三方 丙方 签署推送
            pushMultiContractUrl(StringUtils.collectionToCommaDelimitedString(partC), contractId, contract.getContractName(), company.getName(), 3, contractDetails);
        }
        //将合同详情状态更改为2，上上签签署链接已推送
        contractDetailService.changeStatusByContractId(2, contractId, Constant.SUPER_ADMIN);
    }

    /**
     * 推送多文档合同签署链接
     * @param customerIds
     * @param contractId
     * @param contractName
     * @param companyName
     * @param type
     * @param contractDetails
     */
    private void pushMultiContractUrl(String customerIds, Long contractId, String contractName, String companyName, Integer type, List<ContractDetail> contractDetails) {
        if (StringUtils.hasText(customerIds)) {
            for (String id : removeDuplicateCustomerId(customerIds).split(",")) {
                Customer customer = customerService.getById(Long.parseLong(id));
                SendContract sendContract = new SendContract();
                sendContract.setCatalogName(getBestsignCatalogName(contractId));
                sendContract.setSignerAccount(customer.getAccount());
                sendContract.setVcodeMobile(customer.getMobile());
                if (!USE_FACE) {
                    //测试使用手机验证码签
                    sendContract.setIsFaceAuth("0");
                }

                sendContract.setSid("ZZZC-ZFW-" + contractId + "-" + customer.getId());
                Map<String, SendContract.SignaturePositions> contractParams = new HashMap<>();
                sendContract.setContractParams(contractParams);
                int index = 1;
                for (ContractDetail contractDetail : contractDetails) {
                    List<ContractDetailSigner> contractDetailSigners = contractDetailSignerService.getContractDetailSigners(contractId, contractDetail.getId(), type);
                    for (ContractDetailSigner contractDetailSigner : contractDetailSigners) {
                        SendContract.SignaturePositions signaturePositions = sendContract.new SignaturePositions();
                        if (contractDetailSigner.getSignerId().longValue() == customer.getId().longValue()) {
                            //获取签章坐标
                            List<TempleteRecordSignature> templeteRecordSignatures = templeteRecordSignatureService.getTempleteRecordSignatures(contractDetail.getTempleteRecordId(), contractDetailSigner.getPartType(), contractDetailSigner.getPartName());
                            if (templeteRecordSignatures == null || templeteRecordSignatures.isEmpty()) {
                                throw new BusinessException("未获取到合同模板的签章坐标信息");
                            }
                            for (TempleteRecordSignature templeteRecordSignature : templeteRecordSignatures) {
                                SendContract.SignaturePosition signaturePosition = sendContract.new SignaturePosition();
                                signaturePosition.setPageNum(templeteRecordSignature.getPage() + "");
                                signaturePosition.setX(templeteRecordSignature.getX());
                                signaturePosition.setY(templeteRecordSignature.getY());
                                signaturePositions.getSignaturePositions().add(signaturePosition);
                            }
                            if (!signaturePositions.getSignaturePositions().isEmpty()) {
                                contractParams.put(contractName + index, signaturePositions);
                            }
                        }
                    }
                    index ++;
                }
                wechatApi.pushContractUrl(customer.getWxId(), contractName, companyName, bestsignOpenApi.sendCatalog(sendContract).getData().getUrl());
            }
        }

    }


    /**
     * 推送单文档合同链接
     * @param customerIds
     * @param bestsignContractId
     * @param contractName
     */
    private void pushSingleContractUrl(String customerIds, String bestsignContractId, String contractName, String companyName) {
        if (StringUtils.hasText(customerIds)) {
            for (String id : removeDuplicateCustomerId(customerIds).split(",")) {
                Customer customer = customerService.getById(Long.parseLong(id));
                GetSignURL getSignURL = new GetSignURL();
                getSignURL.setContractId(bestsignContractId);
                getSignURL.setAccount(customer.getAccount());
                BestsignResponse<SendContractResponse> bestsignResponse = bestsignOpenApi.getSignURL(getSignURL);
                wechatApi.pushContractUrl(customer.getWxId(), contractName, companyName, bestsignResponse.getData().getUrl());
            }
        }
    }

    /**
     * 客户ID去重
     * @param customerIds
     * @return
     */
    private String removeDuplicateCustomerId(String customerIds) {
        if (customerIds.indexOf(",") == -1) {
            return customerIds;
        }
        List<String> ids = new ArrayList<>();
        for (String id : customerIds.split(",")) {
            if (!ids.contains(id)) {
                ids.add(id);
            }
        }
        return StringUtils.collectionToCommaDelimitedString(ids);
    }

    /**
     * 重新推送合同签署链接
     * @param contractId
     * @param customerId
     */
    public void repushContractUrl(Long contractId, Long customerId) {
        Contract contract = super.getById(contractId);
        if (contract == null) {
            throw new BusinessException("未查询到合同");
        }
        List<ContractDetail> contractDetails = contractDetailService.getByContractId(contractId);
        if (contractDetails == null || contractDetails.isEmpty()) {
            throw new BusinessException("合同信息为空");
        }
        if (!"3".equals(contract.getStatus())) {
            throw new BusinessException("合同流程状态异常，无法重新推送");
        }
        for (ContractDetail contractDetail : contractDetails) {
            if (contractDetail.getStatus().intValue() != 2) {
                throw new BusinessException("合同状态异常，无法重新推送");
            }
        }
        Customer customer = customerService.getById(customerId);
        if (customer == null) {
            throw new BusinessException("未查询到用户");
        }
        if (customer.getRealnameStatus().intValue() != 1) {
            throw new BusinessException("该用户未实名认证");
        }
        if (contractDetails.size() == 1) {
            //单文档
            pushSingleContractUrl(customer.getId().toString(), contractDetails.get(0).getBestsignContractId(), contract.getContractName(), contract.getClientName());
        } else if (contractDetails.size() > 1) {
            //多文档
            pushMultiContractUrl(customer.getId().toString(), contractId, contract.getContractName(), contract.getClientName(), 2, contractDetails);
        }
    }

    /**
     * 查询合同签署流程列表
     * @param manager
     * @param page
     * @param listMode
     * @param queryItems
     * @param orderField
     * @param order
     * @return
     */
    public IPage<Contract> queryList(SysUser manager, Page<Contract> page, boolean listMode, String queryItems, String orderField, QueryOrderEnum order) {
        QueryWrapper<Contract> queryWrapper = new QueryWrapper<>();
        Map<String, String> fieldColumns = TableFieldColumnsUtils.getInstance().getFieldTableColumns(Contract.class);
        if (listMode) {
            // size 小于 0 不在查询 total 及分页，自动调整为列表模式。
            // 注意！！这个地方自己控制好！！
            page.setSize(-1);
        }
        if (!StringUtils.isEmpty(queryItems)) {
            List<QueryBuilder> queryBuilders = new ArrayList<>();
            String[] queryItemArr = queryItems.split(";");
            if (queryItemArr.length > 0) {
                for (String queryItemStr : queryItemArr) {
                    String[] itemArr = queryItemStr.split(",");
                    if (itemArr.length == 3) {
                        String as = itemArr[1];
                        String params = itemArr[2];
                        if (!StringUtils.isEmpty(params)) {
                            queryBuilders.add(new QueryBuilder(itemArr[0], OperatorEum.valueOf(as), itemArr[2]));
                        }
                    }
                }
            }

            for (QueryBuilder queryBuilder : queryBuilders) {
                //查询字段
                String field = queryBuilder.getField();
                //查询参数值
                String params = queryBuilder.getParams();
                if (fieldColumns.containsKey(field) && !StringUtils.isEmpty(params)) {
                    //表属性
                    String tableColumn = fieldColumns.get(field);
                    if (queryBuilder.getAs() == OperatorEum.EQ) {
                        queryWrapper.eq(tableColumn, params);
                    } else if (queryBuilder.getAs() == OperatorEum.LIKE) {
                        queryWrapper.like(tableColumn, params);
                    } else if (queryBuilder.getAs() == OperatorEum.LIKELEFT) {
                        queryWrapper.likeLeft(tableColumn, params);
                    } else if (queryBuilder.getAs() == OperatorEum.LIKERIGHT) {
                        queryWrapper.likeRight(tableColumn, params);
                    } else if (queryBuilder.getAs() == OperatorEum.GE) {
                        queryWrapper.ge(tableColumn, params);
                    } else if (queryBuilder.getAs() == OperatorEum.LE) {
                        queryWrapper.le(tableColumn, params);
                    }
                }
            }
        }
        authService.setAuthInfo(queryWrapper, manager, Contract.COL_CLIENT_ID, Contract.COL_CREATE_BY);

        if (!StringUtils.isEmpty(orderField)) {
            String[] orderByColumns = orderField.split(",");
            String queryOrderByColumns = "";
            if (orderByColumns.length > 0) {
                StringBuilder sb = new StringBuilder();
                for (String orderByColumn : orderByColumns) {
                    if (fieldColumns.containsKey(orderByColumn)) {
                        sb.append(fieldColumns.get(orderByColumn)).append(",");
                    }
                }
                if (sb.length() > 0) {
                    queryOrderByColumns = sb.deleteCharAt(sb.length() - 1).toString();
                }
            }
            if (!StringUtils.isEmpty(queryOrderByColumns)) {
                if (order == null) {
                    order = QueryOrderEnum.ASC;
                }
                if (order == QueryOrderEnum.ASC) {
                    queryWrapper.orderByAsc(queryOrderByColumns);
                } else if (order == QueryOrderEnum.DESC) {
                    queryWrapper.orderByDesc(queryOrderByColumns);
                }
            }
        }

        return getContractIPage(page, queryWrapper);
    }

    public IPage<Contract> queryContractList(Page<Contract> page, Contract contract){

        return baseMapper.queryContractList(page,contract);
    }


    public boolean addOrUpdate(SysUser manager, Contract contract) {


        return false;
    }

    public Contract info(SysUser manager, Long id) {
        return super.getById(id);
    }

    public boolean delete(SysUser manager, Long[] ids) {
        return super.removeByIds(Arrays.asList(ids));
    }

    public boolean deleteDetail(SysUser manager, Long[] ids) {
        return contractDetailService.removeByIds(Arrays.asList(ids));
    }

    /**
     * 上上签合同签署回调
     * @param contractDetails
     */
    @Transactional(rollbackFor = Exception.class)
    public void completeContract(List<ContractDetail> contractDetails) {
        if (contractDetails != null && !contractDetails.isEmpty()) {
            for (ContractDetail contractDetail : contractDetails) {
                ContractDetail updateEntity = new ContractDetail();
                updateEntity.setId(contractDetail.getId());
                updateEntity.setStatus(3);
                contractDetailService.updateById(updateEntity);
                if (contractDetailService.getNotSignContractCount(contractDetail.getContractId()) == 0) {
                    //合同已全部签署完成，锁定合同
                    lockContract(contractDetail.getContractId());
                }
            }
        }
    }

    /**
     * 合同签署完成锁定合同
     * @param contractId
     */
    private void lockContract(Long contractId) {
        List<ContractDetail> contractDetails = contractDetailService.getByContractId(contractId);
        if (contractDetails != null && !contractDetails.isEmpty()) {
            if (contractDetails.size() == 1) {
                //单文档合同锁定
                LockContract lockContract = new LockContract();
                lockContract.setContractId(contractDetails.get(0).getBestsignContractId());
                bestsignOpenApi.lockContract(lockContract);
            } else if (contractDetails.size() > 1) {
                //多文档锁定
                LockCatalog lockCatalog = new LockCatalog();
                lockCatalog.setCatalogName(getBestsignCatalogName(contractId));
                bestsignOpenApi.lockCatalog(lockCatalog);
            }
            //变更合同状态
            Contract updateEntity = new Contract();
            updateEntity.setId(contractId);
            updateEntity.setStatus("4");
            super.updateById(updateEntity);
        }
    }

    /**
     * 获取上上签多文档合同目录名称
     * @param contractId
     * @return
     */
    public String getBestsignCatalogName(Long contractId) {
        return "ZZZC-ZFW-" + contractId;
    }

    /**
     * 微信订单号
     * @param contractId
     * @return
     */
    public String getWechatPayOrderNo(Long contractId) {
        return "ZZZC-ZFW-" + contractId + "-" + System.currentTimeMillis();
    }

    /**
     * 支付完成
     * @param orderNo
     */
    public void completePay(String orderNo) {
        Contract contract = getByWechatNo(orderNo);
        if (contract == null) {
            contract = super.getById(Long.parseLong(orderNo.split("-")[2]));
            if (contract == null) {
                throw new BusinessException("未找到合同信息");
            }
        }
        Contract updateEntity = new Contract();
        updateEntity.setId(contract.getId());
        updateEntity.setIsPay(1);
        updateEntity.setStatus("3");
        super.updateById(updateEntity);
        //合同已付费，检查合同中签署人是否已实名认证
        if (checkRealname(contract.getId())) {
            //上传合同到上上签
            uploadContract(contract.getId());
        }
    }

    /**
     * 微信支付订单号获取
     * @param orderNo
     * @return
     */
    private Contract getByWechatNo(String orderNo) {
        QueryWrapper<Contract> contractQueryWrapper = new QueryWrapper<>();
        contractQueryWrapper.eq(Contract.COL_WECHAT_NO, orderNo);
        return super.getOne(contractQueryWrapper);
    }

    /**
     * 获取合同预览链接
     * @param contractDetailId
     * @return
     */
    public String getContractPreviewUrl(Long contractDetailId) {
        ContractDetail contractDetail = contractDetailService.getById(contractDetailId);
        if (contractDetail == null) {
            throw new BusinessException(new Result(MessageCode.ERROR, "未查询到合同信息"));
        }
        if (StringUtils.isEmpty(contractDetail.getBestsignContractId())) {
            throw new BusinessException(new Result(MessageCode.ERROR, "未生成合同预览链接"));
        }
        String account = null;
        if (StringUtils.hasText(contractDetail.getPartyA())) {
            for (String companyId : contractDetail.getPartyA().split(",")) {
                Company company = companyService.getById(Long.parseLong(companyId));
                account = company.getBestsignAccount();
            }
        } else {
            if (StringUtils.hasText(contractDetail.getPartyB())) {
                for (String customerId : contractDetail.getPartyB().split(",")) {
                    Customer customer = customerService.getById(Long.parseLong(customerId));
                    account = customer.getAccount();
                }
            }
        }
        PreviewURL previewURL = new PreviewURL();
        previewURL.setAccount(account);
        previewURL.setContractId(contractDetail.getBestsignContractId());
        return bestsignOpenApi.getPreviewURL(previewURL).getData().getUrl();
    }

    /**
     * 获取合同预览链接（多文档合同）
     * @param catalogName
     * @return
     */
    public String getContractPreviewUrl(String account, String catalogName) {
        PreviewURL previewURL = new PreviewURL();
        previewURL.setSignerAccount(account);
        previewURL.setCatalogName(catalogName);
        return bestsignOpenApi.getCatalogPreviewURL(previewURL).getData().getUrl();
    }

    public StatisticsContracts getContractStatistics(SysUser manager) {
        StatisticsContracts statisticsContracts = null;
        if(manager.isHasRole(Constant.SUPER_ADMIN)||manager.isHasRole(Constant.SYSTEM_MANAGER_ID)) {//超级管理员或管理员
            statisticsContracts = baseMapper.getContractStatistics(0);
        }else if(manager.isHasRole(Constant.COMPANY_MANAGER_ID)){ //企业管理,
            statisticsContracts = baseMapper.getContractStatistics(manager.getCompanyId());
        }else{//个人
            statisticsContracts = baseMapper.getContractStatisticsByCreateBy(manager.getUserId());
        }
        return statisticsContracts;
    }

    public List<StatisticsContracts> getContractCompleteTopNum(int num) {
        return baseMapper.getContractCompleteTopNum(num);
    }

    public List<StatisticsContracts> getNearDateContractRecordsData(String startDate, String endDate) {
        List<StatisticsContracts> result = null;
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            Date start = simpleDateFormat.parse(startDate);
            Date end = simpleDateFormat.parse(endDate);
            startDate = simpleDateFormat.format(start);
            endDate = simpleDateFormat.format(end);
            List<StatisticsContracts> statisticsContracts = baseMapper.getNearDateContractRecordsData(startDate,endDate);
            List<String> dateList = getPerDay(startDate, endDate);
            result = new ArrayList<>(dateList.size());
            for (String dateStr : dateList) {
                StatisticsContracts tmp = null;
                for (StatisticsContracts statisticsContracts1 : statisticsContracts) {
                    if (dateStr.equals(statisticsContracts1.getDateTime())) {
                        tmp = statisticsContracts1;
                        break;
                    }
                }
                if (tmp == null) {
                    StatisticsContracts statisticsContracts1 = new StatisticsContracts();
                    statisticsContracts1.setCompletedCount(0);
                    statisticsContracts1.setDateTime(dateStr);
                    statisticsContracts1.setDoingCount(0);
                    statisticsContracts1.setFailCount(0);
                    statisticsContracts1.setTotalCount(0);
                    result.add(statisticsContracts1);
                } else {
                    result.add(tmp);
                }
            }
        } catch (ParseException e) {
            throw new BusinessException("日期格式错误");
        }
        return result;
    }

    /**
     * 获取两个时间之间的每一天
     * @param startDateStr
     * @param endDateStr
     * @return
     */
    private List<String> getPerDay(String startDateStr, String endDateStr) throws ParseException {
        List<String> result = new ArrayList<>();
        result.add(startDateStr);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date startDate = simpleDateFormat.parse(startDateStr);
        Date endDate = simpleDateFormat.parse(endDateStr);
        //定义一个接受时间的集合
        Calendar calBegin = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calBegin.setTime(startDate);
        Calendar calEnd = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calEnd.setTime(endDate);
        // 测试此日期是否在指定日期之后
        while (endDate.after(calBegin.getTime()))  {
            // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
            calBegin.add(Calendar.DAY_OF_MONTH, 1);
            result.add(simpleDateFormat.format(calBegin.getTime()));
        }
        return result;
    }

    public IPage<StatisticsContracts> getContractStatisticsByCompany(Page<StatisticsContracts> page, SysUser manager, Long companyId) {
        //根据角色查询合同统计
        if(manager.isHasRole(Constant.SUPER_ADMIN)||manager.isHasRole(Constant.SYSTEM_MANAGER_ID)) {//超级管理员或管理员
            return baseMapper.getContractStatisticsByCompany(page,null, companyId);
        }else if(manager.isHasRole(Constant.COMPANY_MANAGER_ID)){ //企业管理,
            return baseMapper.getContractStatisticsByCompany(page,manager.getCompanyId(), null);
        }else{//个人
            return baseMapper.getContractStatisticsByCompany(page,null, manager.getUserId());
        }

    }

    public IPage<Contract> queryByContractName(SysUser manager,Page<Contract> page, String contractName) {
        QueryWrapper<Contract> contractQueryWrapper = new QueryWrapper<>();
        contractQueryWrapper.like(Contract.COL_CONTRACT_NAME,contractName);

        if(!manager.isHasRole(Constant.SUPER_ADMIN)){//超级管理员
            QueryWrapper<SysUserRole> managerRoleQueryWrapper = new QueryWrapper<>();
            managerRoleQueryWrapper.eq(SysUserRole.COL_MANAGER_ID, manager.getUserId());
            List<SysUserRole> managerRoles = managerRoleService.list(managerRoleQueryWrapper);
            boolean isCompanyAdmin = false;
            boolean isSystemManager = false;
            if(managerRoles!= null && !managerRoles.isEmpty()){
                List<Long> roleIds = new ArrayList<>();
                for (SysUserRole managerRole : managerRoles) {
                    roleIds.add(managerRole.getRoleId());
                }
                List<SysRole> roleList = (List<SysRole>) roleService.listByIds(roleIds);
                if(roleList!= null && !roleList.isEmpty()){
                    for (SysRole role : roleList) {
                        //如果是企业管理员
                        if(Constant.COMPANY_ADMIN_ALIAS.equals(role.getRoleKey())){
                            isCompanyAdmin = true;
                        }else if(Constant.SYSTEM_MANAGER_ALIAS.equals(role.getRoleKey())){
                            isSystemManager = true;
                        }
                    }
                }
            }
            if(isSystemManager){

            }else{
                if(isCompanyAdmin){
                    contractQueryWrapper.eq(Contract.COL_CLIENT_ID,manager.getCompanyId());
                }else{
                    contractQueryWrapper.eq(Contract.COL_CREATE_BY, manager.getUserId());
                }
            }
        }
        contractQueryWrapper.orderByDesc(Contract.COL_CREATE_TIME);


        return getContractIPage(page, contractQueryWrapper);
    }

    /**
     * 根据微信id查询合同列表
     * @param wxId
     * @return
     */
    public List<WechatContract> getContractListByWxId(String wxId) {
        Customer customer = customerService.getCustomerByWxId(wxId);
        if (customer == null) {
            return new ArrayList<>();
        }
//        QueryWrapper<Contract> contractQueryWrapper = new QueryWrapper<>();
//        contractQueryWrapper.eq(Contract.COL_CUSTOMER_ID, customer.getId())
//                .eq(Contract.COL_STATUS, 4)
//                .orderByDesc(Contract.COL_UPDATE_TIME);
//        List<Contract> contracts = super.list(contractQueryWrapper);
//        if (contracts != null && !contracts.isEmpty()) {
//            List<WechatContract> wechatContracts = new ArrayList<>(contracts.size());
//            contracts.forEach(e -> {
//                WechatContract wechatContract = new WechatContract();
//                BeanUtils.copyProperties(e, wechatContract);
//                wechatContracts.add(wechatContract);
//            });
//            return wechatContracts;
//        }
//        return new ArrayList<>();
        return super.getBaseMapper().getWechatContractByCustomerId(customer.getId());
    }

    public String getContractPreviewUrlByWxId(String wxId, Long contractId) {
        Customer customer = customerService.getCustomerByWxId(wxId);
        if (customer == null) {
            throw new BusinessException(MessageCode.ERROR, "非法请求");
        }
//        QueryWrapper<Contract> contractQueryWrapper = new QueryWrapper<>();
//        contractQueryWrapper.eq(Contract.COL_ID, contractId)
//                .eq(Contract.COL_CUSTOMER_ID, customer.getId());
//        if (super.count(contractQueryWrapper) == 0) {
//            throw new BusinessException(MessageCode.ERROR, "非法请求");
//        }

        QueryWrapper<ContractDetailSigner> contractDetailSignerQueryWrapper = new QueryWrapper<>();
        contractDetailSignerQueryWrapper.eq(ContractDetailSigner.COL_CONTRACT_ID, contractId)
                .eq(ContractDetailSigner.COL_SIGNER_ID, customer.getId());
        if (contractDetailSignerService.count(contractDetailSignerQueryWrapper) == 0) {
            throw new BusinessException(MessageCode.ERROR, "非法请求");
        }
        List<ContractDetail> contractDetails = contractDetailService.getByContractId(contractId);
        if (contractDetails == null || contractDetails.isEmpty()) {
            throw new BusinessException(MessageCode.ERROR, "未查询到合同");
        }
        if (contractDetails.size() == 1) {
            return getContractPreviewUrl(contractDetails.get(0).getId());
        } else {
            return getContractPreviewUrl(customer.getAccount(), getBestsignCatalogName(contractId));
        }
    }

    /**
     * 下载已签署合同
     * @param id
     */
    public void downloadContract(HttpServletResponse response, Long id) {
        Contract contract = super.getById(id);
        if (contract == null) {
            throw new BusinessException(MessageCode.ERROR, "未找到合同");
        }
        if (!"4".equals(contract.getStatus())) {
            throw new BusinessException(MessageCode.ERROR, "合同未签署完成，无法下载");
        }
        response.setContentType("application/force-download");
        List<ContractDetail> contractDetails = contractDetailService.getByContractId(id);
        if (!contractDetails.isEmpty() && contractDetails.size() == 1) {
            //单文档合同下载
            String bestsignContractId = null;
            for (ContractDetail contractDetail : contractDetails) {
                if (StringUtils.hasText(contractDetail.getBestsignContractId())) {
                    bestsignContractId = contractDetail.getBestsignContractId();
                    break;
                }
            }
            if (bestsignContractId == null) {
                throw new BusinessException(MessageCode.ERROR, "系统异常，下载失败");
            }
            byte[] data = bestsignOpenApi.contractDownload(bestsignContractId);
            try {
                response.addHeader("Content-Disposition", "attachment;fileName=" + new String(contract.getContractName().getBytes("utf-8"), "ISO8859-1") + ".pdf");
            } catch (UnsupportedEncodingException e) {

            }
            try {
                response.getOutputStream().write(data);
            } catch (IOException e) {
                throw new BusinessException(MessageCode.ERROR, "系统异常，下载失败");
            }
        } else if (!contractDetails.isEmpty() && contractDetails.size() > 1) {
            //多文档合同下载
            String zipPath = FileUtils.getLocation() + FileUtils.FileType.TMP.getValue() + "/" + contract.getId() + "--" + contract.getContractName() + ".zip";
            File zipFile = new File(zipPath);
            File parentDir = zipFile.getParentFile();
            if (!parentDir.exists()) {
                parentDir.mkdirs();
            }
            try (
                    FileOutputStream fos = new FileOutputStream(zipFile);
                    ZipOutputStream zos = new ZipOutputStream(fos)

            ) {
                for (ContractDetail contractDetail : contractDetails) {
                    if (StringUtils.hasText(contractDetail.getBestsignContractId())) {
                        byte[] data = bestsignOpenApi.contractDownload(contractDetail.getBestsignContractId());
                        zos.putNextEntry(new ZipEntry(System.currentTimeMillis() + ".pdf"));
                        zos.write(data);
                    }
                }
            } catch (IOException e) {
                throw new BusinessException(MessageCode.ERROR, "系统异常，下载失败");
            }
            try (FileInputStream fis = new FileInputStream(zipFile)) {
                response.addHeader("Content-Disposition", "attachment;fileName=" + new String(contract.getContractName().getBytes("utf-8"), "ISO8859-1") + ".zip");
                response.setHeader("Content-Length","" + zipFile.length());
                IOUtils.copy(fis, response.getOutputStream());
                response.flushBuffer();
            } catch (IOException e) {
                throw new BusinessException(MessageCode.ERROR, "系统异常，下载失败");
            }
            zipFile.deleteOnExit();
        } else {
            //异常情况
            throw new BusinessException(MessageCode.ERROR, "系统异常，下载失败");
        }
    }

    /**
     * 个人签署合同成功
     * @param bestsignContractId 上上签合同id
     * @param bestsignAccount 上上签账号
     */
    public void signSuccess(String bestsignContractId, String bestsignAccount) {
        List<ContractDetail> contractDetails = contractDetailService.getByBestsignContractId(bestsignContractId);
        Long contractId = null;
        if (contractDetails != null && !contractDetails.isEmpty()) {
            contractId = contractDetails.get(0).getContractId();
        }
        if (contractId == null) {
            log.warn("合同bestsignContractId【{}】未找到", bestsignContractId);
            return;
        }
        Customer customer = customerService.getByBestsignAccount(bestsignAccount);
        if (customer == null) {
            log.warn("用户bestsignAccount【{}】未找到", bestsignAccount);
            return;
        }
        contractDetailSignerService.signed(contractId, customer.getId());
    }

    /**
     * 签署者信息查询
     * @param contractId
     * @return
     */
    public List<SignerDTO> getSignerDTOList(Long contractId) {
        List<ContractDetailSigner> contractDetailSigners = contractDetailSignerService.getByContractId(contractId);
        List<SignerDTO> signerDTOS = new ArrayList<>(contractDetailSigners.size());
        for (ContractDetailSigner contractDetailSigner : contractDetailSigners) {
            SignerDTO signerDTO = new SignerDTO();
            if (contractDetailSigner.getPartType().intValue() == 1) {
                //企业
                Company company = companyService.getById(contractDetailSigner.getSignerId());
                if (company != null) {
                    signerDTO.setId(company.getId());
                    signerDTO.setName(company.getName());
                } else {
                    signerDTO.setId(contractDetailSigner.getSignerId());
                }
            } else if (contractDetailSigner.getPartType().intValue() == 2) {
                //个人
                Customer customer = customerService.getById(contractDetailSigner.getSignerId());
                if (customer != null) {
                    signerDTO.setId(customer.getId());
                    signerDTO.setName(customer.getName());
                    signerDTO.setIdentity(customer.getIdentity());
                    signerDTO.setMobile(customer.getMobile());
                    signerDTO.setRealnameStatus(customer.getRealnameStatus());
                } else {
                    signerDTO.setId(contractDetailSigner.getSignerId());
                }
            }
            signerDTO.setPartName(contractDetailSigner.getPartName());
            signerDTO.setPartType(contractDetailSigner.getPartType());
            signerDTO.setSignStatus(contractDetailSigner.getSignStatus());
            signerDTO.setSignTime(contractDetailSigner.getSignTime());
            signerDTOS.add(signerDTO);
        }
        return signerDTOS;
    }



    /**
     * 修改合同状态为失败
     * @param contractId
     */
    @Transactional
    public void changeContractStatusFail(Long contractId) {
        UpdateWrapper<Contract> contractUpdateWrapper = new UpdateWrapper<>();
        contractUpdateWrapper.set(Contract.COL_STATUS, 6)
                .eq(Contract.COL_ID, contractId);
        super.update(contractUpdateWrapper);
        UpdateWrapper<ContractDetail> contractDetailUpdateWrapper = new UpdateWrapper<>();
        contractDetailUpdateWrapper.set(ContractDetail.COL_STATUS, 4)
                .eq(ContractDetail.COL_CONTRACT_ID, contractId);
        contractDetailService.update(contractDetailUpdateWrapper);
    }

    /**
     * 作废合同操作
     * @param contractId
     * @param manager
     */
    public void cancelContract(Long contractId, SysUser manager) {
        Contract contract = getById(contractId);
        if (contract == null) {
            throw new BusinessException("合同不存在");
        }
        cancelContract(contract, manager.getUserId());
    }

    /**
     * 合同作废
     * @param contract
     * @param updateManagerId
     */
    @Transactional
    public void cancelContract(Contract contract, Long updateManagerId) {
        if ("3".equals(contract.getStatus())) {
            List<ContractDetail> contractDetails = contractDetailService.getByContractId(contract.getId());
            for (ContractDetail contractDetail : contractDetails) {
                try {
                    bestsignOpenApi.cancel(new ContractId(contractDetail.getBestsignContractId()));
                } catch (Exception e) {
                    log.warn("上上签合同取消失败", e);
                }
            }
        }
        //修改合同流程为作废
        changeStatusByContractId(5, contract.getId(), updateManagerId);
        //修改合同详情为作废
        contractDetailService.changeStatusByContractId(9, contract.getId(), updateManagerId);
    }

    /**
     * 修改合同流程状态
     * @param status
     * @param contractId
     * @param updateManagerId
     */
    private void changeStatusByContractId(Integer status, Long contractId, Long updateManagerId) {
        UpdateWrapper<Contract> contractUpdateWrapper = new UpdateWrapper<>();
        contractUpdateWrapper.set(Contract.COL_STATUS, status)
                .set(Contract.COL_UPDATE_TIME, new Date())
                .set(Contract.COL_UPDATE_BY, updateManagerId)
                .eq(Contract.COL_ID, contractId);
        super.update(contractUpdateWrapper);
    }

    /**
     * 修改付款状态
     * @param isPay
     * @param contractId
     * @param updateManagerId
     */
    public void changeIsPayByContractId(Integer isPay, Long contractId, Long updateManagerId) {
        UpdateWrapper<Contract> contractUpdateWrapper = new UpdateWrapper<>();
        contractUpdateWrapper.set(Contract.COL_IS_PAY, isPay)
                .set(Contract.COL_UPDATE_TIME, new Date())
                .set(Contract.COL_UPDATE_BY, updateManagerId)
                .eq(Contract.COL_ID, contractId);
        super.update(contractUpdateWrapper);

    }

    public IPage<Contract> unCompleteContractPage(SysUser manager, Page<Contract> page, boolean listMode, int datumStatus, int status, String orderField, String order) {
        QueryWrapper<Contract> queryWrapper = new QueryWrapper<>();
        if (listMode) {
            // size 小于 0 不在查询 total 及分页，自动调整为列表模式。
            // 注意！！这个地方自己控制好！！
            page.setSize(-1);
        }
        if(manager.isHasRole(Constant.SUPER_ADMIN)||manager.isHasRole(Constant.SYSTEM_MANAGER_ID)) {//超级管理员或管理员

        }else if(manager.isHasRole(Constant.COMPANY_MANAGER_ID)){ //企业管理,
            queryWrapper.eq(Contract.COL_CLIENT_ID,manager.getCompanyId());
        }else{//个人
            queryWrapper.eq(Contract.COL_CREATE_BY,manager.getUserId());
        }
        queryWrapper.eq(Contract.COL_DATUM_STATUS,datumStatus);
        if(status == 0){
            queryWrapper.le(Contract.COL_STATUS,4);
        }else if(status == 1){
            queryWrapper.eq(Contract.COL_STATUS,4);
        }
        queryWrapper.orderByDesc(Contract.COL_CREATE_TIME);

        return getContractIPage(page, queryWrapper);
    }

    private IPage<Contract> getContractIPage(Page<Contract> page, QueryWrapper<Contract> queryWrapper) {
        IPage<Contract> iPage = baseMapper.selectPage(page, queryWrapper);
        iPage.getRecords().forEach(e -> {
            SysUser m = managerService.getById(e.getCreateBy());
            if (m != null) {
                e.setCreator(m.getNickName());
            }
        });
        return iPage;
    }

    /**
     * 我的合同信息分页查询
     * @param manager
     * @param page
     * @param queryItems
     * @return
     */
    public IPage<MyContractStatisticsBean> myContractStatisticsPage(SysUser manager, Page<MyContractStatisticsBean> page, String queryItems) {
        QueryWrapper<Contract> contractQueryWrapper = new QueryWrapper<>();
        Page<Contract> contractPage = new Page<>(page.getCurrent(), page.getSize());
        contractQueryWrapper.eq(Contract.COL_STATUS, 4);
        contractQueryWrapper.eq(Contract.COL_CREATE_BY,manager.getUserId());
        contractQueryWrapper.orderByDesc(Contract.COL_CREATE_TIME);

        Map<String, String> fieldColumns = TableFieldColumnsUtils.getInstance().getFieldTableColumns(Contract.class);
        if (!StringUtils.isEmpty(queryItems)) {
            List<QueryBuilder> queryBuilders = new ArrayList<>();
            String[] queryItemArr = queryItems.split(";");
            if (queryItemArr.length > 0) {
                for (String queryItemStr : queryItemArr) {
                    String[] itemArr = queryItemStr.split(",");
                    if (itemArr.length == 3) {
                        String as = itemArr[1];
                        String params = itemArr[2];
                        if (!StringUtils.isEmpty(params)) {
                            queryBuilders.add(new QueryBuilder(itemArr[0], OperatorEum.valueOf(as), itemArr[2]));
                        }
                    }
                }
            }

            for (QueryBuilder queryBuilder : queryBuilders) {
                //查询字段
                String field = queryBuilder.getField();
                //查询参数值
                String params = queryBuilder.getParams();
                if (fieldColumns.containsKey(field) && !StringUtils.isEmpty(params)) {
                    //表属性
                    String tableColumn = fieldColumns.get(field);
                    if (queryBuilder.getAs() == OperatorEum.EQ) {
                        contractQueryWrapper.eq(tableColumn, params);
                    } else if (queryBuilder.getAs() == OperatorEum.LIKE) {
                        contractQueryWrapper.like(tableColumn, params);
                    } else if (queryBuilder.getAs() == OperatorEum.LIKELEFT) {
                        contractQueryWrapper.likeLeft(tableColumn, params);
                    } else if (queryBuilder.getAs() == OperatorEum.LIKERIGHT) {
                        contractQueryWrapper.likeRight(tableColumn, params);
                    } else if (queryBuilder.getAs() == OperatorEum.GE) {
                        contractQueryWrapper.ge(tableColumn, params);
                    } else if (queryBuilder.getAs() == OperatorEum.LE) {
                        contractQueryWrapper.le(tableColumn, params);
                    }
                }
            }
        }


//        authService.setAuthInfo(contractQueryWrapper, manager, Contract.COL_CLIENT_ID, Contract.COL_CUSTOMER_ID);

        IPage<Contract> iPage = super.page(contractPage, contractQueryWrapper);
        IPage<MyContractStatisticsBean> result = new Page<>(iPage.getCurrent(), iPage.getSize(), iPage.getTotal());
        if (iPage.getTotal() > 0) {
            List<MyContractStatisticsBean> myContractStatisticsBeans = new ArrayList<>(Long.valueOf(iPage.getSize()).intValue());
            SysUser contractManager;
            for (Contract contract : iPage.getRecords()) {
                MyContractStatisticsBean tmp = new MyContractStatisticsBean();
                BeanUtils.copyProperties(contract, tmp);
                contractManager = managerService.getById(tmp.getCreateBy());
                if (contractManager != null) {
                    tmp.setCreateName(contractManager.getNickName());
                }
                myContractStatisticsBeans.add(tmp);
            }
            result.setRecords(myContractStatisticsBeans);
        }
        return result;
    }

    /**
     * 导出数据
     * @param manager
     * @param queryItems
     * @return
     */
    public List<MyContractStatisticsBean> exportMyContractStatistics(SysUser manager, String queryItems) {
        QueryWrapper<Contract> contractQueryWrapper = new QueryWrapper<>();
        contractQueryWrapper.eq(Contract.COL_STATUS, 4);
        contractQueryWrapper.orderByDesc(Contract.COL_CREATE_TIME);


        Map<String, String> fieldColumns = TableFieldColumnsUtils.getInstance().getFieldTableColumns(Contract.class);
        if (!StringUtils.isEmpty(queryItems)) {
            List<QueryBuilder> queryBuilders = new ArrayList<>();
            String[] queryItemArr = queryItems.split(";");
            if (queryItemArr.length > 0) {
                for (String queryItemStr : queryItemArr) {
                    String[] itemArr = queryItemStr.split(",");
                    if (itemArr.length == 3) {
                        String as = itemArr[1];
                        String params = itemArr[2];
                        if (!StringUtils.isEmpty(params)) {
                            queryBuilders.add(new QueryBuilder(itemArr[0], OperatorEum.valueOf(as), itemArr[2]));
                        }
                    }
                }
            }

            for (QueryBuilder queryBuilder : queryBuilders) {
                //查询字段
                String field = queryBuilder.getField();
                //查询参数值
                String params = queryBuilder.getParams();
                if (fieldColumns.containsKey(field) && !StringUtils.isEmpty(params)) {
                    //表属性
                    String tableColumn = fieldColumns.get(field);
                    if (queryBuilder.getAs() == OperatorEum.EQ) {
                        contractQueryWrapper.eq(tableColumn, params);
                    } else if (queryBuilder.getAs() == OperatorEum.LIKE) {
                        contractQueryWrapper.like(tableColumn, params);
                    } else if (queryBuilder.getAs() == OperatorEum.LIKELEFT) {
                        contractQueryWrapper.likeLeft(tableColumn, params);
                    } else if (queryBuilder.getAs() == OperatorEum.LIKERIGHT) {
                        contractQueryWrapper.likeRight(tableColumn, params);
                    } else if (queryBuilder.getAs() == OperatorEum.GE) {
                        contractQueryWrapper.ge(tableColumn, params);
                    } else if (queryBuilder.getAs() == OperatorEum.LE) {
                        contractQueryWrapper.le(tableColumn, params);
                    }
                }
            }
        }


        authService.setAuthInfo(contractQueryWrapper, manager, Contract.COL_CLIENT_ID, Contract.COL_CUSTOMER_ID);
        List<Contract> contracts = super.list(contractQueryWrapper);
        List<MyContractStatisticsBean> myContractStatisticsBeans = new ArrayList<>();
        if (contracts != null && !contracts.isEmpty()) {
            for (Contract contract : contracts) {
                MyContractStatisticsBean tmp = new MyContractStatisticsBean();
                BeanUtils.copyProperties(contract, tmp);
                myContractStatisticsBeans.add(tmp);

            }
        }
        return myContractStatisticsBeans;
    }

    public List<MyContractStatisticsBean> exportContractInfoStatistics(SysUser manager, Long templateRecordId, String startDate, String endDate) {
        List<Long> companyIds = authService.getManagerComanyIds(manager);
        List<MyContractStatisticsBean> myContractStatisticsBeans = super.getBaseMapper().getContractByTemplateRecordId(manager.getUserId(), companyIds, templateRecordId, startDate, endDate);
        if (myContractStatisticsBeans != null) {
            myContractStatisticsBeans.stream().forEach(myContractStatisticsBean -> {
                Map<String, Object> map = new HashMap<>();
                List<ContractPlaceholder> contractPlaceholders = contractPlaceholderService.getByTemplateRecordId(templateRecordId);
                if (contractPlaceholders != null) {
                    contractPlaceholders.stream().forEach(contractPlaceholder -> {
                        map.put(contractPlaceholder.getPlaceholderBelong() + "." + contractPlaceholder.getPlaceholderName(), contractPlaceholder.getPlaceholderValue());
                    });
                }
                myContractStatisticsBean.setContractPlaceholders(map);
            });
        }
        return myContractStatisticsBeans;
    }

    /**
     * 获取刷脸签视频
     * @param contractDetailId
     * @param customerId
     * @return
     */
    public CredentialVerifyVideo getCredentialVerifyVideo(Long contractDetailId, Long customerId) {
        ContractDetail contractDetail = contractDetailService.getById(contractDetailId);
        if (contractDetail == null) {
            throw new BusinessException("合同不存在");
        }
        Customer customer = customerService.getById(customerId);
        if (customer == null) {
            throw new BusinessException("用户不存在");
        }
        OrderNo orderNo = bestsignOpenApi.getFaceAuthOrderNo(new ContractId(contractDetail.getBestsignContractId(), customer.getAccount())).getData();
        orderNo.setDataType("3");
        CredentialVerifyVideo credentialVerifyVideo = bestsignOpenApi.downloadCredentialVerifyVideo(orderNo).getData();
        try {
            convertBase642File(credentialVerifyVideo);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return credentialVerifyVideo;
    }

    /**
     * 下载签约视频
     * @param credentialVerifyVideo
     * @return
     */
    public File convertBase642File(CredentialVerifyVideo credentialVerifyVideo) throws IOException {
        if (StringUtils.hasText(credentialVerifyVideo.getPhoto())) {
            Files.write(Paths.get("C:\\Users\\wuyufei\\Desktop\\1.jpg"), Base64.decodeBase64(credentialVerifyVideo.getPhoto()), StandardOpenOption.CREATE);
        }
        if (StringUtils.hasText(credentialVerifyVideo.getVideo())) {
            Files.write(Paths.get("C:\\Users\\wuyufei\\Desktop\\1.mp4"), Base64.decodeBase64(credentialVerifyVideo.getVideo()), StandardOpenOption.CREATE);
        }
        return null;
    }

    /**
     * 下载存证页
     * @param response
     * @param id
     */
    public void downloadAttachment(HttpServletResponse response, Long id) {
        Contract contract = super.getById(id);
        if (contract == null) {
            throw new BusinessException(MessageCode.ERROR, "未找到合同");
        }
        if (!"4".equals(contract.getStatus())) {
            throw new BusinessException(MessageCode.ERROR, "合同未签署完成，无法下载");
        }
        response.setContentType("application/force-download");
        List<ContractDetail> contractDetails = contractDetailService.getByContractId(id);
        byte[] data = null;
        if (!contractDetails.isEmpty() && contractDetails.size() == 1) {
            //单文档合同下载
            String bestsignContractId = null;
            for (ContractDetail contractDetail : contractDetails) {
                if (StringUtils.hasText(contractDetail.getBestsignContractId())) {
                    bestsignContractId = contractDetail.getBestsignContractId();
                    break;
                }
            }
            if (bestsignContractId == null) {
                throw new BusinessException(MessageCode.ERROR, "系统异常，下载失败");
            }
            data = bestsignOpenApi.downloadAttachment(bestsignContractId);
        } else if (!contractDetails.isEmpty() && contractDetails.size() > 1) {
            //多文档合同下载
            data = bestsignOpenApi.downloadCatalogAttachment(getBestsignCatalogName(id));
        } else {
            //异常情况
            throw new BusinessException(MessageCode.ERROR, "系统异常，下载失败");
        }
        try {
            response.addHeader("Content-Disposition", "attachment;fileName=" + new String((contract.getContractName() + "存证页").getBytes("utf-8"), "ISO8859-1") + ".pdf");
            response.getOutputStream().write(data);
        } catch (IOException e) {
            throw new BusinessException(MessageCode.ERROR, "系统异常，下载失败");
        }

    }

	public byte[][] downloadContract(Long id) {
		List<ContractDetail> contractDetails = contractDetailService.getByContractId(id);
		byte[][] result = new byte[contractDetails.size()][];
		for (int i = 0; i < contractDetails.size(); i ++) {
			result[i] = bestsignOpenApi.contractDownload(contractDetails.get(i).getBestsignContractId());
		}
		return result;
	}


//    @DataScope(deptAlias = "d", userAlias = "m")
//    public IPage<MyContractStatisticsBean> contractInfoStatisticsPage(SysUser manager, Page<MyContractStatisticsBean> page, MyContractStatisticsBean contractQueryBo) {
//
//        QueryWrapper<Contract> contractQueryWrapper = new QueryWrapper<>();
//        Page<Contract> contractPage = new Page<>(page.getCurrent(), page.getSize());
//        contractQueryWrapper.eq(Contract.COL_STATUS, 4);
//        contractQueryWrapper.orderByDesc(Contract.COL_CREATE_TIME);
//
//        Map<String, String> fieldColumns = TableFieldColumnsUtils.getInstance().getFieldTableColumns(Contract.class);
//        if (!StringUtils.isEmpty(queryItems)) {
//            List<QueryBuilder> queryBuilders = new ArrayList<>();
//            String[] queryItemArr = queryItems.split(";");
//            if (queryItemArr.length > 0) {
//                for (String queryItemStr : queryItemArr) {
//                    String[] itemArr = queryItemStr.split(",");
//                    if (itemArr.length == 3) {
//                        String as = itemArr[1];
//                        String params = itemArr[2];
//                        if (!StringUtils.isEmpty(params)) {
//                            queryBuilders.add(new QueryBuilder(itemArr[0], OperatorEum.valueOf(as), itemArr[2]));
//                        }
//                    }
//                }
//            }
//
//            for (QueryBuilder queryBuilder : queryBuilders) {
//                //查询字段
//                String field = queryBuilder.getField();
//                //查询参数值
//                String params = queryBuilder.getParams();
//                if (fieldColumns.containsKey(field) && !StringUtils.isEmpty(params)) {
//                    //表属性
//                    String tableColumn = fieldColumns.get(field);
//                    if (queryBuilder.getAs() == OperatorEum.EQ) {
//                        contractQueryWrapper.eq(tableColumn, params);
//                    } else if (queryBuilder.getAs() == OperatorEum.LIKE) {
//                        contractQueryWrapper.like(tableColumn, params);
//                    } else if (queryBuilder.getAs() == OperatorEum.LIKELEFT) {
//                        contractQueryWrapper.likeLeft(tableColumn, params);
//                    } else if (queryBuilder.getAs() == OperatorEum.LIKERIGHT) {
//                        contractQueryWrapper.likeRight(tableColumn, params);
//                    } else if (queryBuilder.getAs() == OperatorEum.GE) {
//                        contractQueryWrapper.ge(tableColumn, params);
//                    } else if (queryBuilder.getAs() == OperatorEum.LE) {
//                        contractQueryWrapper.le(tableColumn, params);
//                    }
//                }
//            }
//        }
//
//
//        authService.setAuthInfo(contractQueryWrapper, manager, Contract.COL_CLIENT_ID, Contract.COL_CUSTOMER_ID);
//
//        IPage<MyContractStatisticsBean> iPage = baseMapper.contractInfoStatisticsPage(manager.getUserId(),page,contractQueryBo);
//        IPage<MyContractStatisticsBean> result = new Page<>(iPage.getCurrent(), iPage.getSize(), iPage.getTotal());
//        if (iPage.getTotal() > 0) {
//            List<MyContractStatisticsBean> myContractStatisticsDTOS = new ArrayList<>(Long.valueOf(iPage.getSize()).intValue());
//            SysUser contractManager;
//            for (Contract contract : iPage.getRecords()) {
//                MyContractStatisticsBean tmp = new MyContractStatisticsBean();
//                BeanUtils.copyProperties(contract, tmp);
//                contractManager = managerService.getById(tmp.getCreateBy());
//                if (contractManager != null) {
//                    tmp.setCreateName(contractManager.getName());
//                }
//                myContractStatisticsDTOS.add(tmp);
//            }
//            result.setRecords(myContractStatisticsDTOS);
//        }
//
//        return iPage;
//    }
}
